package com.atguigu.srb.core.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.srb.base.result.ResponseEnum;
import com.atguigu.srb.base.util.JwtUtils;
import com.atguigu.srb.base.util.SrbAssert;
import com.atguigu.srb.core.hfb.FormHelper;
import com.atguigu.srb.core.hfb.HfbConst;
import com.atguigu.srb.core.hfb.RequestHelper;
import com.atguigu.srb.core.pojo.entity.*;
import com.atguigu.srb.core.mapper.LendItemMapper;
import com.atguigu.srb.core.pojo.vo.InvestVO;
import com.atguigu.srb.core.service.*;
import com.atguigu.srb.core.util.LendNoUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 标的出借记录表 服务实现类
 * </p>
 *
 * @author Atguigu
 * @since 2023-03-25
 */
@Service
@Slf4j
public class LendItemServiceImpl extends ServiceImpl<LendItemMapper, LendItem> implements LendItemService {
    @Resource
    UserInfoService userInfoService;
    @Resource
    LendService lendService;
    @Resource
    TransFlowService transFlowService;
    @Resource
    UserAccountService userAccountService;
    @Resource
    DictService dictService;
    //投资
    @Override
    public String invest(InvestVO investVO, String token) {
        //1、验证登录+用户账户状态
        UserInfo userInfo = userInfoService.checkUserStatus(token);
        //2、验证用户账户余额:  可以根据userId查询账户对象
        UserAccount userAccount = userAccountService.getUserAccountByUserId(userInfo.getId());
        //investVO.getInvestAmount().compareTo(userAccount.getAmount())<=0 表示 投资金额小于或者等于账户总金额
        SrbAssert.assertTrue(investVO.getInvestAmount().compareTo(userAccount.getAmount())<=0,
                ResponseEnum.NOT_SUFFICIENT_FUNDS_ERROR);
        //3、验证标的状态+是否满标

        Long lendId = investVO.getLendId();
        Lend lend = lendService.getById(lendId);
        SrbAssert.assertTrue(investVO.getInvestAmount().compareTo(lend.getLowestAmount())>=0,
                ResponseEnum.LEND_INVEST_LOWEST_ERROR);
        SrbAssert.assertTrue(lend.getStatus()==1,ResponseEnum.LEND_INVEST_ERROR);
        SrbAssert.assertTrue(lend.getAmount().compareTo(lend.getInvestAmount().add(investVO.getInvestAmount()))>=0,
                ResponseEnum.LEND_FULL_SCALE_ERROR);
        //4、构建表单字符串返回
        Map<String, Object> params = new HashMap<>();
        params.put("agentId",HfbConst.AGENT_ID);
        params.put("voteBindCode",userInfo.getBindCode());//投资人 hfb账户 bindCode
        //查询借款人 会员信息
        UserInfo borrwerUserInfo = userInfoService.getById(lend.getUserId());
        params.put("benefitBindCode",borrwerUserInfo.getBindCode());// 借款人 hfb账户 bindCode   需要通过lend中的借款人会员id查询
        //多个投资将来 通过标的的编号来关联： 标的放款时  根据lendNo去hfb中放款
        params.put("agentProjectCode",lend.getLendNo());// lend就是一个标的 一个项目
        params.put("agentProjectName",lend.getTitle());//标的名称
        String lendItemNo = LendNoUtils.getLendItemNo();
        params.put("agentBillNo", lendItemNo);//商户订单号  本次操作的唯一的交易号
        params.put("voteAmt",investVO.getInvestAmount());//投资金额
        params.put("votePrizeAmt","0");
        params.put("voteFeeAmt","0");
        params.put("projectAmt",lend.getAmount());//项目总金额
//        params.put("note","");
        params.put("notifyUrl",HfbConst.INVEST_NOTIFY_URL);
        params.put("returnUrl",HfbConst.INVEST_RETURN_URL);
        params.put("timestamp",System.currentTimeMillis());
        params.put("sign", RequestHelper.getSign(params));
        // 本处设置的签名：工具类使用params中的参数+本地秘钥 通过MD5算法生成的签名

        //5、保存交易日志:
        TransFlow transflow = new TransFlow();
        transflow.setUserId(userInfo.getId());
        transflow.setUserName(userInfo.getName());
        transflow.setTransNo(lendItemNo);
        transflow.setTransType(3);//3：投资
        transflow.setTransTypeName("投标");
        transflow.setTransAmount(investVO.getInvestAmount());
        transFlowService.save(transflow);
        //6、创建投资记录保存：
        LendItem lendItem = new LendItem();
        lendItem.setLendItemNo(lendItemNo);
        lendItem.setLendId(lend.getId());
        lendItem.setInvestUserId(userInfo.getId());
        lendItem.setInvestName(userInfo.getName());
        lendItem.setInvestAmount(investVO.getInvestAmount());
        lendItem.setLendYearRate(lend.getLendYearRate());
        lendItem.setInvestTime(new Date());
        lendItem.setLendStartDate(lend.getLendStartDate());
        lendItem.setLendEndDate(lend.getLendEndDate());
        //预期收益：
        BigDecimal income = lendService.income(investVO.getInvestAmount(), lend.getLendYearRate(),
                lend.getPeriod(), lend.getReturnMethod());
        lendItem.setExpectAmount(income);
        lendItem.setRealAmount(new BigDecimal(0));
        lendItem.setStatus(0);
        this.save(lendItem);
        return FormHelper.buildForm(HfbConst.INVEST_URL,params);
    }

    @Override
    public String investNotify(Map<String, Object> map) {
        //1、校验签名:  使用map再次生成签名 和map中原有的签名比较
        if(!RequestHelper.isSignEquals(map)){
            log.error("投资回调失败,签名错误:{}", JSON.toJSONString(map));
            return "fail";
        }
        //2、校验响应状态码：hfb业务处理状态码
        String resultCode = map.get("resultCode").toString();//0001=投标成功
        String resultMsg = map.get("resultMsg").toString();
        String agentBillNo = map.get("agentBillNo").toString();//商户订单号：lendItemNo
        String agentProjectCode = map.get("agentProjectCode").toString();//项目编号：lendNo
        String voteBindCode = map.get("voteBindCode").toString();//投资人 hfb账户bindCode
        String voteAmt = map.get("voteAmt").toString();//投资金额
        //3、校验投资金额 保证幂等性
        //获取投资记录 或者 交易日志
        TransFlow transFlow = transFlowService.getOne(Wrappers.lambdaQuery(TransFlow.class)
                .eq(TransFlow::getTransNo, agentBillNo));
        if(transFlow==null){
            //交易号不存在
            log.error("投资回调失败,交易编号错误: {}", JSON.toJSONString(map));
            return "fail";
        }
        if(transFlow.getStatus()==1){
            //交易号存在 并且已完成
            return "success";
        }
        if(transFlow.getTransAmount().compareTo(new BigDecimal(voteAmt))!=0){
            log.error("投资回调失败,hfb投资金额错误: {}", JSON.toJSONString(map));
            return "fail";
        }
        //5、更新日志状态、更新投资记录为已支付状态
        transFlow.setMemo(JSON.toJSONString(map));
        transFlow.setStatus(1);
        transFlow.setCreateTime(null);
        transFlow.setUpdateTime(null);
        transFlowService.updateById(transFlow);
        //agentBillNo
        this.update(Wrappers.lambdaUpdate(LendItem.class)
            .eq(LendItem::getLendItemNo ,agentBillNo )
            .set(LendItem::getStatus , 1));

        //6、冻结投资人账户投资金额
        // 投资人账户余额扣除投资金额  冻结金额增加投资金额
        //transFlow
        userAccountService.updateInvestAmountByUserId(transFlow.getUserId(),voteAmt);
        //7、更新标的的已投金额+投资人数
        //String transNo = transFlow.getTransNo(); //lendItemNo
        // agentProjectCode  LendNo
        lendService.updateInvestAmountAndNum(agentProjectCode,voteAmt);

        return "success";
    }

    @Override
    public Page<LendItem> investList(String token, Integer pageNum, Integer pageSize) {
        Long userId = JwtUtils.getUserId(token);

        Page<LendItem> page = this.page(new Page<LendItem>(pageNum, pageSize), Wrappers.lambdaQuery(LendItem.class)
                .eq(LendItem::getInvestUserId, userId));

        page.getRecords().forEach(lendItem -> {
            //查询lend对象
            Lend lend = lendService.getById(lendItem.getLendId());
            //期数 年化率  状态 还款方式 资金用途
            Map map = new HashMap<String,String>();
            map.put("period",lend.getPeriod()+"个月");
            map.put("lendYearRate",lend.getLendYearRate()+"%");
            map.put("status",lendItem.getStatus()==0?"待支付"
                                :(lendItem.getStatus()==1?"已支付":"已还款"));
            map.put("returnMethod",dictService.getDictNameByDictCodeAndValue("returnMethod",lend.getReturnMethod()));
//            map.put("moneyUse",dictService.getDictNameByDictCodeAndValue("moneyUse",lend.get()));
            lendItem.setParams(map);
        });

        return page;
    }




}
